# scenes/views.py

from django.shortcuts import get_object_or_404
from django.utils import timezone
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from datetime import datetime
from django.utils.timezone import localtime

from .models import Scene, Action, Trigger, SceneExecutionLog
from apps.user.models import Family, FamilyMember
from apps.device_simulation.models import Device, DeviceStateHistory

# ---------- 常量 / 工具函数 ----------
ERROR_CODES = {
    'INVALID_PARAM': status.HTTP_422_UNPROCESSABLE_ENTITY,
    'UNAUTHORIZED': status.HTTP_401_UNAUTHORIZED,
    'FORBIDDEN': status.HTTP_403_FORBIDDEN,
    'NOT_FOUND': status.HTTP_404_NOT_FOUND,
    'SERVER_ERROR': status.HTTP_500_INTERNAL_SERVER_ERROR,
}


def ok(data=None, code=200):
    return Response({'ok': True, 'data': data}, status=code)


def err(code_key, message):
    return Response({'ok': False, 'code': code_key, 'message': message},
                    status=ERROR_CODES.get(code_key, 500))


def get_user_family_info(user):
    """获取用户家庭信息的工具函数"""
    try:
        family_member = FamilyMember.objects.get(user=user)
        user_family = family_member.family
        family_members = FamilyMember.objects.filter(family=user_family)
        family_users = [m.user for m in family_members]
        
        family_info = {
            'id': user_family.id,
            'name': user_family.name,
            'user_role': family_member.role,
            'member_count': len(family_users)
        }
        return family_users, family_info
    except FamilyMember.DoesNotExist:
        return [user], None


# ---------- 场景管理 ----------

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def create_scene(request):
    """POST /scenes  创建场景"""
    name = request.data.get('name')
    priority = request.data.get('priority', 5)
    enabled = request.data.get('enabled', False)

    if not name:
        return err('INVALID_PARAM', 'name 为必填字段')

    try:
        family_users, family_info = get_user_family_info(request.user)
        
        # 校验家庭内场景名唯一性
        if Scene.objects.filter(owner__in=family_users, name=name).exists():
            scope = "该家庭中" if family_info else "你"
            return err('INVALID_PARAM', f'{scope}已存在名为 "{name}" 的场景')

    except Exception as e:
        return err('SERVER_ERROR', f'获取家庭信息失败: {str(e)}')

    # 创建场景
    scene = Scene.objects.create(
        name=name,
        owner=request.user,
        priority=priority,
        enabled=enabled,
    )

    # 构造返回数据
    data = {
        'id': scene.id,
        'name': scene.name,
        'priority': scene.priority,
        'enabled': scene.enabled
    }
    if family_info:
        data['family'] = family_info

    return ok(data, code=status.HTTP_201_CREATED)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def list_scenes(request):
    """GET /scenes?page=&page_size=  场景列表 - 返回用户所在家庭所有成员的场景"""
    page = int(request.query_params.get('page', 1))
    page_size = int(request.query_params.get('page_size', 10))
    
    try:
        family_users, family_info = get_user_family_info(request.user)
        # 查询该家庭所有成员的场景
        qs = Scene.objects.filter(owner__in=family_users).order_by('-priority', 'id')
        
    except Exception as e:
        return err('SERVER_ERROR', f'获取场景列表失败: {str(e)}')
    
    total = qs.count()
    start = (page - 1) * page_size
    end = start + page_size
    
    scenes = []
    for s in qs[start:end]:
        # 判断场景是否属于当前用户
        is_owner = s.owner == request.user
        
        scenes.append({
            'id': s.id,
            'name': s.name,
            'priority': s.priority,
            'enabled': s.enabled,
            'owner': s.owner.username,  # 显示场景创建者
            'is_owner': is_owner,  # 标识是否为当前用户创建
        })
    
    response_data = {
        'total': total, 
        'scenes': scenes
    }
    
    # 如果用户属于家庭，添加家庭信息
    if family_info:
        response_data['family_info'] = family_info
    
    return ok(response_data)


@api_view(['PUT'])
@permission_classes([IsAuthenticated])
def move_scene(request, scene_id):
    """
    PUT /scenes/{scene_id}/move
    移动场景上下位置，交换优先级
    """
    scene = get_object_or_404(Scene, pk=scene_id)
    action = request.data.get('action')
    if action not in ['move_up', 'move_down']:
        return err('INVALID_PARAM', 'action 必须是 move_up 或 move_down')

    # 获取当前用户家庭内的所有场景（或仅用户本人的场景）
    try:
        family_users, _ = get_user_family_info(request.user)
        qs = Scene.objects.filter(owner__in=family_users).exclude(id=scene.id)
    except Exception as e:
        return err('SERVER_ERROR', f'获取家庭信息失败: {str(e)}')

    # 寻找相邻的场景
    if action == 'move_up':
        neighbor = qs.filter(priority__gt=scene.priority).order_by('priority').first()
    else:  # move_down
        neighbor = qs.filter(priority__lt=scene.priority).order_by('-priority').first()

    if not neighbor:
        return err('INVALID_PARAM', f'无法{action}，已在边界位置')

    # 交换优先级
    old_priority = scene.priority
    neighbor_priority = neighbor.priority
    scene.priority, neighbor.priority = neighbor_priority, old_priority
    scene.save()
    neighbor.save()

    return ok({
        'scene_id': scene.id,
        'scene_name': scene.name,
        'action': action,
        'swapped_with': {
            'id': neighbor.id,
            'name': neighbor.name,
        },
        'new_priority': scene.priority,
        'neighbor_new_priority': neighbor.priority
    })


@api_view(['GET', 'PATCH', 'DELETE'])
@permission_classes([IsAuthenticated])
def scene_detail(request, scene_id):
    """场景详情管理"""
    scene = get_object_or_404(Scene, pk=scene_id)
    family_users, _ = get_user_family_info(scene.owner)
    
    if request.method == 'GET':
        """GET /scenes/{scene_id}  场景详情"""
        actions = [
            {'device_id': a.device_id, 'command': a.command}
            for a in scene.actions.all()
        ]
        triggers = [
            {'type': t.type, 'config': t.config}
            for t in scene.triggers.all()
        ]
        data = {
            'id': scene.id,
            'name': scene.name,
            'priority': scene.priority,
            'enabled': scene.enabled,
            'actions': actions,
            'triggers': triggers
        }
        return ok(data)
    
    elif request.method == 'PATCH':
        """PATCH /scenes/{scene_id}  局部更新"""

        if scene.owner != request.user or request.user not in family_users:
            return err('FORBIDDEN', '无权限修改场景')

        # 这里只允许修改 enabled、priority、name
        for field in ('name', 'priority', 'enabled'):
            if field in request.data:
                setattr(scene, field, request.data[field])
        scene.updated_at = timezone.now()
        scene.save()
        return ok({
            'id': scene.id,
            'name': scene.name,
            'priority': scene.priority,
            'enabled': scene.enabled
        })
    
    elif request.method == 'DELETE':
        """DELETE /scenes/{scene_id}  删除场景"""
        if scene.owner != request.user or request.user not in family_users:
            return err('FORBIDDEN', '无权限删除场景')
        scene_name = scene.name
        scene.delete()
        return ok({'deleted': scene_id, 'name': scene_name}, code=status.HTTP_204_NO_CONTENT)


# ---------- 场景设备管理 ----------

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def add_device(request, scene_id):
    """POST /scenes/{scene_id}/devices  添加设备到场景"""
    scene = get_object_or_404(Scene, pk=scene_id)
    users, _ = get_user_family_info(scene.owner)
    # 场景拥有者或同一家族成员可操作
    if request.user != scene.owner and request.user not in users:
        return err('FORBIDDEN', '无权限修改该场景设备')

    device_id = request.data.get('device_id')
    if device_id is None:
        return err('INVALID_PARAM', 'device_id为必填')
    
    try:
        device = Device.objects.get(id=device_id)
    except Device.DoesNotExist:
        return err('NOT_FOUND', f'设备 {device_id} 不存在')
    
    # 使用设备当前状态作为默认 command
    default_state = device.state.state_json if device.state and isinstance(device.state.state_json, dict) else {}
    print(f"Adding device {device_id} with default state: {default_state}")

    action = Action.objects.create(
        scene=scene,
        device=device,
        command=default_state
    )

    return ok({
        'scene_id': scene.id,
        'device_id': device.id,
        'default_command': default_state
    }, code=status.HTTP_201_CREATED)



@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def remove_device(request, scene_id, device_id):
    """DELETE /scenes/{scene_id}/devices/{device_id}  从场景中删除设备"""
    scene = get_object_or_404(Scene, pk=scene_id)
    users, _ = get_user_family_info(scene.owner)
    if request.user != scene.owner and request.user not in users:
        return err('FORBIDDEN', '无权限删除该场景设备')
    try:
        Device.objects.get(id=device_id)
    except Device.DoesNotExist:
        return err('NOT_FOUND', f'设备 {device_id} 不存在')
    action = get_object_or_404(Action, scene=scene, device_id=device_id)
    action.delete()
    return ok({'removed_device_id': device_id}, code=status.HTTP_204_NO_CONTENT)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def set_device_state(request, scene_id, device_id):
    """POST /scenes/{scene_id}/devices/{device_id}/set_state 设置设备目标状态"""
    scene = get_object_or_404(Scene, pk=scene_id)
    state = request.data.get('state')

    if not state:
        return err('INVALID_PARAM', 'state 为必填字段')

    try:
        device = Device.objects.get(id=device_id)
    except Device.DoesNotExist:
        return err('NOT_FOUND', f'设备 {device_id} 不存在')

    # 检查用户是否有权限
    users, _ = get_user_family_info(scene.owner)
    if request.user != scene.owner and request.user not in users:
        return err('FORBIDDEN', '无权限修改该场景设备')

    # 创建或更新 Action 实例
    action, created = Action.objects.update_or_create(
        scene=scene,
        device_id=device_id,
        defaults={'command': state}
    )

    return ok({
        'scene_id': scene.id,
        'device_id': device_id,
        'state': state,
        'created': created
    })


@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def delete_device_state(request, scene_id, device_id):
    """DELETE /scenes/{scene_id}/devices/{device_id}/delete_state 删除设备目标状态"""
    scene = get_object_or_404(Scene, pk=scene_id)
    try:
        action = Action.objects.get(scene=scene, device_id=device_id)
    except Action.DoesNotExist:
        return err('NOT_FOUND', f'设备 {device_id} 在场景 {scene_id} 中没有目标状态')

    # 检查用户是否有权限
    users, _ = get_user_family_info(scene.owner)
    if request.user != scene.owner and request.user not in users:
        return err('FORBIDDEN', '无权限删除该场景设备')

    action.delete()
    return ok({'removed_device_id': device_id})

# ---------- 激活 & 当前生效场景 ----------

def activate_scene(scene, user, invoker=SceneExecutionLog.Invoker.AUTO):
    """激活指定场景并禁用当前用户或其家庭下的其他场景"""
    users, _ = get_user_family_info(user)
    Scene.objects.filter(owner__in=users, enabled=True).exclude(id=scene.id).update(enabled=False)
    scene.enabled = True
    scene.save()

    results = []
    success_count = 0
    
    for action in scene.actions.all():
        device_id = action.device_id
        command = action.command
        try:
            device = Device.objects.get(id=device_id)
            device.apply_state(
                new_state=command,
                source=DeviceStateHistory.Source.SCENE
            )
            success_count += 1
            results.append({
                'device_id': device_id,
                'status': 'success',
                'applied_state': command
            })
        except Device.DoesNotExist:
            results.append({
                'device_id': device_id,
                'status': 'failed',
                'detail': 'Device not found'
            })
        except ValueError as ve:
            results.append({
                'device_id': device_id,
                'status': 'failed',
                'detail': str(ve)
            })
        except Exception as e:
            results.append({
                'device_id': device_id,
                'status': 'failed',
                'detail': f'Unexpected error: {str(e)}'
            })

    SceneExecutionLog.objects.create(
        scene=scene,
        invoker=invoker,
        status=SceneExecutionLog.Status.SUCCESS if success_count == len(results) else 
               SceneExecutionLog.Status.PARTIAL_SUCCESS if success_count > 0 else 
               SceneExecutionLog.Status.ERROR,
        detail=f"Executed {success_count}/{len(results)} actions successfully"
    )
    
    return results


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def switch_scene(request, scene_id):
    """
    POST /scenes/{scene_id}/activate
    激活场景并控制其设备，且禁用当前用户或其家庭下的其他场景
    """
    scene = get_object_or_404(Scene, pk=scene_id)
    
    # 调用 activate_scene 函数
    results = activate_scene(scene, request.user, SceneExecutionLog.Invoker.MANUAL)

    return ok({
        'scene_id': scene.id,
        'scene_name': scene.name,
        'result_summary': f"{sum(1 for r in results if r['status'] == 'success')}/{len(results)} success",
        'device_results': results
    })


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def active_scene(request):
    """GET /scenes/active  获取当前生效场景 - 基于用户所在家庭"""
    try:
        family_users, family_info = get_user_family_info(request.user)
        
        # 查询该家庭所有成员的启用场景，按优先级排序
        scene = Scene.objects.filter(
            owner__in=family_users,
            enabled=True
        ).order_by('-priority').first()
        
    except Exception as e:
        return err('SERVER_ERROR', f'获取活动场景失败: {str(e)}')
    
    if not scene:
        response_data = {'message': '无可用场景'}
        if family_info:
            response_data['family_info'] = family_info
        return err('NOT_FOUND', response_data)
    
    # 获取场景的动作和触发器
    try:
        actions = [
            {
                'device_id': a.device_id, 
                'command': a.command
            } for a in scene.actions.all()
        ]
    except Exception:
        actions = []
    
    try:
        triggers = [
            {
                'type': t.type, 
                'config': t.config
            } for t in scene.triggers.all()
        ]
    except Exception:
        triggers = []
    
    data = {
        'id': scene.id,
        'name': scene.name,
        'priority': scene.priority,
        'enabled': scene.enabled,
        'owner': scene.owner.username,  # 添加场景创建者信息
        'is_owner': scene.owner == request.user,  # 标识是否为当前用户创建
        'actions': actions,
        'triggers': triggers,
    }
    
    # 如果用户属于家庭，添加家庭信息
    if family_info:
        data['family_info'] = family_info
    
    return ok(data)





# ---------- 触发器管理 ----------

@api_view(['GET'])
def triggers_metadata(request):
    """GET /triggers/metadata  获取触发器模板"""
    metadata = [
        {'type': 'time_range', 'config_keys': ['start', 'end', 'days'], 'description': '根据时间范围自动激活场景'},
    ]
    return ok(metadata)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def add_trigger(request, scene_id):
    """POST /scenes/{scene_id}/triggers  设置触发器"""
    scene = get_object_or_404(Scene, pk=scene_id)
    users, _ = get_user_family_info(scene.owner)
    if scene.owner != request.user and request.user not in users:
        return err('FORBIDDEN', '无权限修改场景触发器')

    t_type = request.data.get('type')
    config = request.data.get('config')
    if not t_type or not isinstance(config, dict):
        return err('INVALID_PARAM', 'type 和 config 必填且格式合法')
    
    trigger = Trigger.objects.create(scene=scene, type=t_type, config=config)
    return ok({'id': trigger.id, 'type': t_type, 'config': config}, code=status.HTTP_201_CREATED)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def check_time_trigger(request):
    """
    POST /triggers/check-time
    用于定时任务检测当前时间是否命中某些 time_range 触发器
    触发器逻辑：
    - 没有场景启用时，激活触发器对应的场景
    - 有场景启用时，切换到触发器对应的场景
    """
    now = localtime()
    now_time = now.strftime("%H:%M")
    now_weekday = now.strftime("%a").lower()  # "Mon" -> "mon"

    # 获取所有 time_range 触发器及其场景
    triggers = Trigger.objects.filter(type='time_range').select_related('scene')

    activated_scene = None
    device_states = []

    for t in triggers:
        config = t.config
        start = config.get('start')
        end = config.get('end')
        days = config.get('days', [])  # 可能为空

        # 如果设置了具体星期，且今天不在其中，跳过
        if days and now_weekday not in days:
            continue

        # 检查时间是否在范围内
        if start <= now_time <= end or (start > end and (now_time >= start or now_time <= end)):
            scene = t.scene
            
            # 获取该场景所属用户的家庭信息
            users, _ = get_user_family_info(scene.owner)
            
            # 检查是否已有启用的场景
            current_enabled_scene = Scene.objects.filter(
                owner__in=users, 
                enabled=True
            ).first()
            
            # 如果没有启用的场景，或者当前启用的场景不是触发器对应的场景，则激活
            if not current_enabled_scene or current_enabled_scene.id != scene.id:
                # 调用 activate_scene 函数激活场景
                activate_scene(scene, scene.owner, SceneExecutionLog.Invoker.AUTO)
                activated_scene = scene
                
                # 获取设备状态
                for action in scene.actions.all():
                    try:
                        device = Device.objects.get(id=action.device_id)
                        device_states.append({
                            'device_id': device.id,
                            'applied_command': action.command,
                            'current_state': device.state
                        })
                    except Device.DoesNotExist:
                        device_states.append({
                            'device_id': action.device_id,
                            'applied_command': action.command,
                            'current_state': None
                        })
                break  # 只激活一个场景

    if activated_scene:
        return ok({
            "activated_scene_id": activated_scene.id,
            "activated_scene_name": activated_scene.name,
            "device_states": device_states
        })
    else:
        return ok({
            "activated_scene_id": None,
            "message": "No scene activated"
        })